package com.bsj.power.pls.queue;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.util.HexUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.bsj.consumerQ.function.HandleRunT;
import com.bsj.consumerQ.method.QueueAndRunT;
import com.bsj.power.common.config.cached.*;
import com.bsj.power.common.config.redis.RTKConstant;
import com.bsj.power.common.config.redis.RedisConstant;
import com.bsj.power.common.config.rocketmq.producer.BaseMqPushUtil;
import com.bsj.power.common.constant.AlarmEnum;
import com.bsj.power.common.constant.MqTopicAndTagConstants;
import com.bsj.power.common.constant.NumericalConstants;
import com.bsj.power.common.constant.UWBPosConstant;
import com.bsj.power.common.def.dto.cardReport.BindCardDTO;
import com.bsj.power.common.def.dto.locationDevice.TagMsgDTO;
import com.bsj.power.common.def.entity.alarmReport.AlarmReport;
import com.bsj.power.common.def.entity.job.WorkPersonnel;
import com.bsj.power.common.def.entity.locationDevice.LocationDevice;
import com.bsj.power.common.def.entity.log.VideoOpLog;
import com.bsj.power.common.def.entity.personnel.Personnel;
import com.bsj.power.common.def.enums.VideoOpTypeEnum;
import com.bsj.power.common.def.vo.WebSocketMsgVO;
import com.bsj.power.common.def.vo.pls.httpVo.HttpTagPosVO;
import com.bsj.power.common.def.vo.pls.uwb.UWBExtendVO;
import com.bsj.power.common.http.ExternalAccessHttp;
import com.bsj.power.common.mapper.AlarmReportMapper;
import com.bsj.power.common.mapper.VideoOpLogMapper;
import com.bsj.power.common.util.DataUtil;
import com.bsj.power.common.util.ExceptionUtil;
import com.bsj.power.common.util.PosUtil;
import com.bsj.power.pls.config.net.netty.protocol.UWBAck;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author LiJiaXin
 * @version 1.0.0
 * @description SosAlarmQueue
 * @time 2024/10/8 14:15
 */
@Slf4j
@Component
public class SosAlarmQueue extends QueueAndRunT<TagMsgDTO> {

    /**
     * SOS报警标识
     */
    private static final String CALL_FLAG = "Call";
    /**
     * 数据透传
     */
    private static final String TRANSMIT_DATA = "TransmitData";

    /**
     * true代表核电环境，false代表公司测试环境
     */
    @Value("${systemFlag}")
    private Boolean systemFlag;

    @Value("${myUrl.ipHost}")
    private String ipHost;

    @Autowired
    private BindCardCached bindCardCached;

    @Autowired
    private PersonnelCached personnelCached;

    @Autowired
    private WorkPersonnelCached workPersonnelCached;

    @Autowired
    private LocationDeviceCached locationDeviceCached;

    @Autowired
    private PathCached pathCached;

    @Autowired
    private BaseMqPushUtil baseMqPushUtil;

    @Autowired
    private RedisCached redisCached;

    @Autowired
    private MsgQueue msgQueue;

    @Resource
    private AlarmReportMapper alarmReportMapper;

    @Autowired
    private VideoOpLogMapper videoOpLogMapper;

    public void start() {
        start("sosAlarmQueue", new HandleRunT<TagMsgDTO>() {
            @Override
            public void doRun(List<TagMsgDTO> list) {
                if (list == null) {
                    return;
                }
                try {
                    List<AlarmReport> insertSosAlarmList = new ArrayList<>();
                    for (TagMsgDTO tagMsgDTO : list) {
                        String deviceName = tagMsgDTO.getSn();
                        String id = tagMsgDTO.getId() + "";
                        JSONObject jsonObject = JSONObject.parseObject(tagMsgDTO.getData());
                        if (jsonObject == null) {
                            continue;
                        }
                        //事件名，首字母大写，TransmitData 表示透传数据，
                        // Call 标识标签上行呼叫，
                        // CancelCall 表示标签取消上行呼叫，
                        // ConfirmCall 表示标签确认用户下行呼叫
                        String name = jsonObject.getString("name");
                        if (StringUtils.isBlank(name)) {
                            continue;
                        }
                        LocationDevice locationDevice = locationDeviceCached.hgetLocationDeviceInfo(deviceName);
                        switch (name) {
                            case CALL_FLAG:
                                break;
                            case TRANSMIT_DATA:
                                //TransmitData 时不为空，其他为空
                                JSONObject tranData = jsonObject.getJSONObject("data");
                                if (tranData == null) {
                                    break;
                                }
                                //"hex"|"utf8"|"base64", 默认为''"表示 base64 编码
                                String codec = tranData.getString("codec");
                                //透传数据
                                String data = tranData.getString("data");
                                if (data == null) {
                                    break;
                                }
                                byte[] alarmByte = null;
                                if (codec != null && "hex".equalsIgnoreCase(codec)) {
                                    alarmByte = HexUtil.decodeHex(data);
                                } else {
                                    alarmByte = Base64.decode(data);
                                }
                                log.info("数据透传信息接收: {}", HexUtil.encodeHexStr(alarmByte, false));
                                int cmdType = Byte.toUnsignedInt(alarmByte[1]);
                                switch (cmdType) {
                                    case 0xE9:
                                        //经、纬度状态信息及报警信息上报
                                        sosAlarmStatus(alarmByte, deviceName, insertSosAlarmList,
                                                bindCardCached, workPersonnelCached, personnelCached,
                                                baseMqPushUtil, redisCached, msgQueue, tagMsgDTO,
                                                pathCached, ipHost, id, locationDevice, systemFlag);
                                        break;
                                    case 0xEA:
                                        //RTK广播数据下发结果应答
                                        transmitRTKAck(alarmByte, redisCached, ipHost, id, deviceName);
                                        break;
                                    default:
                                        log.info("未知类型");
                                        break;
                                }
                                break;
                            default:
                                break;
                        }
                    }
                    if (!insertSosAlarmList.isEmpty()) {
                        //根据设备号去重
                        ArrayList<AlarmReport> alarmReportArrays = insertSosAlarmList.stream().collect(Collectors.collectingAndThen(
                                Collectors.toMap(AlarmReport::getDeviceName, Function.identity(), (existing, replacement) -> existing),
                                map -> new ArrayList<>(map.values())));
                        //报表存储
                        alarmReportArrays.stream().forEach(item -> {
//                            alarmReportMapper.insert(item);
                            VideoOpLog videoOpLog = new VideoOpLog();
                            int type = VideoOpTypeEnum.CALL_HELP_ALARM.getOpType();
                            videoOpLog.setDeviceId(item.getDeviceName());
                            videoOpLog.setName(VideoOpTypeEnum.getByValue(type));
                            videoOpLog.setOpUserId(2L);
                            videoOpLog.setOpUserName("admin");
                            videoOpLog.setOpType(type);
                            videoOpLog.setOpTime(item.getBeginTime());
                            videoOpLog.setContent(VideoOpTypeEnum.CALL_HELP_ALARM.getOpTypeValue() + "：" + item.getDeviceName());
                            videoOpLog.setNickName(item.getNikeName());
                            videoOpLogMapper.insert(videoOpLog);

                        });
                    }
                } catch (Exception e) {
                    log.error("SosAlarmQueue is fail: {}", ExceptionUtil.getStackStr(e));
                    return;
                }
            }
        });
    }

    /**
     * 经、纬度状态信息及报警信息上报处理
     * @param alarmByte
     * @param deviceName
     * @param insertSosAlarmList
     * @param bindCardCached
     * @param workPersonnelCached
     * @param personnelCached
     * @param baseMqPushUtil
     * @param redisCached
     * @param msgQueue
     * @param tagMsgDTO
     * @throws Exception
     */
    public static void sosAlarmStatus(byte[] alarmByte, String deviceName, List<AlarmReport> insertSosAlarmList,
                                      BindCardCached bindCardCached, WorkPersonnelCached workPersonnelCached,
                                      PersonnelCached personnelCached, BaseMqPushUtil baseMqPushUtil,
                                      RedisCached redisCached, MsgQueue msgQueue, TagMsgDTO tagMsgDTO,
                                      PathCached pathCached, String ipHost, String id,
                                      LocationDevice locationDevice, Boolean systemFlag) throws Exception{
        UWBExtendVO extendVO = UWBAck.analysisAlarmInfo(alarmByte);
        if (extendVO == null) {
            return;
        }
        log.info("deviceName: {}, UWBExtendVO: {}", deviceName, JSON.toJSONString(extendVO));
        //SOS报警位
        Integer sosAlarm = extendVO.getSosAlarm();
        if (sosAlarm != null && sosAlarm == 1) {
            //收到报警才返回应答
            String reBackStr = "24E90301CFFF";
            if (systemFlag) {
                ExternalAccessHttp.transmitDataHttpPut("B", ipHost, id, reBackStr);
            }
            Integer alarmLevel = pathCached.hgetAlarmLevel(AlarmEnum.CALL_HELP_ALARM.getCode());
            Date now = new Date();
            AlarmReport alarmReport = new AlarmReport();
            alarmReport.setAlarmType(AlarmEnum.CALL_HELP_ALARM.getCode());
            alarmReport.setDeviceName(deviceName);
            alarmReport.setNikeName(locationDevice == null ? "" : locationDevice.getNikeName());
            alarmReport.setDeviceType(2);
            alarmReport.setBeginTime(now);
            alarmReport.setEndTime(now);
            alarmReport.setAlertLevel(alarmLevel);
            Integer personType = 2;
            //绑卡信息
            BindCardDTO bindCardDTO = bindCardCached.hgetBindCardInfo(RedisConstant.BIND_CARD_REDIS_DEVICE_NAME_KEY + deviceName);
            if (bindCardDTO != null) {
                String empNo = bindCardDTO.getEmpNo();
                //负责人员信息
                Personnel personnel = personnelCached.hgetPersonnelInfo(empNo);
                if (personnel != null) {
                    personType = 1;
                }
                //作业人员信息
                WorkPersonnel workPersonnel = workPersonnelCached.getWorkPersonnelInfo(empNo);
                if (personnel != null || workPersonnel != null) {
                    alarmReport.setPersonnelId(personnel != null ? personnel.getPersonnelId() : workPersonnel.getWorkPersonnelId());
                    alarmReport.setPersonnelName(personnel != null ? personnel.getName() : workPersonnel.getName());
                }
            }
            alarmReport.setPersonType(personType);
            insertSosAlarmList.add(alarmReport);
            //报警提醒
            WebSocketMsgVO webSocketMsgVO = WebSocketMsgVO.builder()
                    .msgType(7)
                    .obj(alarmReport)
                    .build();
            baseMqPushUtil.sendTopicBytes(MqTopicAndTagConstants.SYSTEM_WEB_SERVER_CHANGE_TOPIC,
                    MqTopicAndTagConstants.SYSTEM_WEB_PRODUCT_CHANGE_TAG, JSON.toJSONBytes(webSocketMsgVO));
        }
        //RTK定位信息,经纬度
        Double lon = extendVO.getLon() / 1000000.000000;
        Double lat = extendVO.getLat() / 1000000.000000;
        //将经纬度转换为x,y,z
        double[] posData = PosUtil.AssessPos(lon, lat, 2d);
//        Integer bdPosState = extendVO.getBdPosState();
//        if (bdPosState != null && bdPosState == 1) {
            //使用RTK北斗卫星定位数据
            long millis = System.currentTimeMillis();
            TagMsgDTO msgDTO = new TagMsgDTO();
            //标识是RTK卫星定位
            msgDTO.setType(UWBPosConstant.MSG_TYPE_POS);
            msgDTO.setSn(deviceName);
            msgDTO.setNow(millis / 1000);
            HttpTagPosVO httpTagPosVO = new HttpTagPosVO();
            httpTagPosVO.setPos(posData);
            httpTagPosVO.setMapId(1);
            httpTagPosVO.setSn(deviceName);
            httpTagPosVO.setTime(millis);
            httpTagPosVO.setPosType(1);
            httpTagPosVO.setLat(lat);
            httpTagPosVO.setLon(lon);
            msgDTO.setData(JSON.toJSONString(httpTagPosVO));

            //TODO
            //同步给到网页展示
            WebSocketMsgVO webSocketMsgVO = WebSocketMsgVO.builder()
                    .msgType(NumericalConstants.ONE)
                    .obj(httpTagPosVO)
                    .build();
            String jsonString = JSON.toJSONString(webSocketMsgVO);
            baseMqPushUtil.sendTopicBytes(MqTopicAndTagConstants.SYSTEM_WEB_SERVER_CHANGE_TOPIC,
                    MqTopicAndTagConstants.SYSTEM_WEB_PRODUCT_CHANGE_TAG, jsonString.getBytes());

//            msgQueue.push(tagMsgDTO);
//            redisCached.set(UWBPosConstant.REDIS_UWB_GPS_POS_FLAG_KEY + deviceName, "2", 5);
//        } else {
            //变成室内后则删除室外定位标识,切换回室内定位
//            redisCached.del(UWBPosConstant.REDIS_UWB_GPS_POS_FLAG_KEY + deviceName);
//            log.info("RTK不定位数据丢弃: {}", extendVO);
//        }
    }

    /**
     * 处理RTK应答内容，有需要补发的应答需要进行二次补发
     * @param rtkAckByte
     * @param redisCached
     * @param ipHost
     * @throws Exception
     */
    public static void transmitRTKAck(byte[] rtkAckByte, RedisCached redisCached,
                                      String ipHost, String id, String deviceName) throws Exception{
        Map<Integer, List<Integer>> numList = UWBAck.rtkAck(rtkAckByte);
        if (numList == null) {
            return;
        }
        numList.forEach((k, v) -> {
            String hex = redisCached.get(RTKConstant.RTK_BROADCAST_TEMP_KEY + k);
            byte[] bytes = HexUtil.decodeHex(hex);
            //将数据分包
            byte[][] divData = DataUtil.divideData(bytes, 50);
            for (Integer now : v) {
                //当前包内容
                byte[] nowData = divData[now - 1];
                byte[] rtkSend = UWBAck.rtkSend(nowData, now, divData.length, k);
                String rtkSendStr = HexUtil.encodeHexStr(rtkSend);
                boolean b = ExternalAccessHttp.transmitDataHttpPut("C", ipHost, id, rtkSendStr);
                log.info("RTK数据广播补发, SN: {}, 透传状态: {}, 透传数据: {}", deviceName, b, rtkSendStr);
            }
        });
    }

    public static void main(String[] args) {
        //{\"id\":6,\"name\":\"T6\",\"sn\":\"9324135059403350195\",\"type\":3,\"data\":{\"name\":\"TransmitData\",\"data\":{\"data\":\"JOkXAgEBWim4Bsv2OAAD6SQQCRFFIAGfLQo=\"}}}
//        String str = "{\"type\":14,\"data\":\"{\\\"id\\\":9,\\\"name\\\":\\\"T9\\\",\\\"sn\\\":\\\"3759033888827777870\\\",\\\"type\\\":3,\\\"data\\\":{\\\"name\\\":\\\"Call\\\"}}\"}";
//        JSONObject object = JSONObject.parseObject(str);
//        //14表示标签相关消息，7表示告警消息
//        Integer type = object.getInteger("type");
//        String data = object.getString("data");
//        if (type == 14) {
//            TagMsgDTO tagMsgDTO = JSONObject.parseObject(data, TagMsgDTO.class);
//            log.info("事件信息：{}", tagMsgDTO);
//        }

        //{"data":"{\"id\":6,\"name\":\"T6\",\"sn\":\"9324135059403350194\",\"type\":3,\"data\":{\"name\":\"TransmitData\",\"data\":{\"data\":\"JOkXAQEBWim4Bsv2OAAD6SQQCRFFIAGfLQo=\"}}}","type":14}
        String al = "24e9170101015a29b806cbf6380003e9241009114520019f2d0a";
        byte[] alBytes = HexUtil.decodeHex(al);
        String encode = Base64.encode(alBytes);
        //JOkXAgEBWim4Bsv2OAAD6SQQCRFFIAGfLQo=
        System.out.println(encode);
        String s = "JOkXAQEBWim4Bsv2OAAD6SQQCRFFIAGfLQo=";
        byte[] decode = Base64.decode(s);
        String decodeStr = HexUtil.encodeHexStr(decode);
        System.out.println(decodeStr);
    }

}
